package speech.nbc;

import java.util.*;
import java.io.*;

import be.ac.ulg.montefiore.run.jahmm.ObservationInteger;
import be.ac.ulg.montefiore.run.jahmm.io.ObservationIntegerReader;
import be.ac.ulg.montefiore.run.jahmm.io.ObservationSequencesReader;


public class NaiveBayesClassifier {

	HashMap<Tag, Category> categories;
	ArrayList<Utterance> taggedUtterances;
	HashMap<Tag, Double> scores;
	String tagFolderPath;

	public NaiveBayesClassifier(String tagFolderPath) {
		taggedUtterances = new ArrayList<Utterance>();
		categories = new HashMap<Tag, Category>();
		scores = new HashMap<Tag, Double>();
		this.tagFolderPath = tagFolderPath;
	}

	public void LoadTagFile (String filepath, Tag t)
	{
		try {
			BufferedReader br = new BufferedReader(new FileReader(filepath));
			String line;
		
			while ((line = br.readLine()) != null) {
				Utterance tu = new Utterance(line);
				//out.println(clean(tu.textContent));
				addTaggedUtterance(tu, t);
			}
		}
		catch (Exception e)
		{
			System.out.println("Error loading file\n");
		}
	}
	
	public void addTaggedUtterance(Utterance u, Tag t) {
		taggedUtterances.add(u);
		
		if (categories.get(t) == null) {
			categories.put(t, new Category(t));
		}
		
		categories.get(t).AddWords(u.getWords());
	}

	public void addTaggedUtterances(ArrayList<Utterance> utt, Tag t) {
		for (Utterance u : utt)
			addTaggedUtterance(u, t);
	}
	
	public int CountAllWords()
	{
		int nrWords = 0;
		Set<Tag> tags = categories.keySet();
		for (Tag t : tags)
		{
			nrWords += categories.get(t).GetTotalWords();
		}
		
		return nrWords;
	}

	public String classifyUtterance(String utterance) {
		scores.clear();
		Utterance u = new Utterance(utterance);

		Category c =  new Category(new Tag("none"));
		c.AddWords(u.getWords());
		
		Set<Tag> tags = categories.keySet();
		for (Tag t : tags)
		{
			scores.put(t, 0.0);
		}
		
		for(String w : c.GetWords())
		{
			for (Tag t : tags)
			{
				int count = categories.get(t).GetWordCount(w);
				if (0 < count)
				{
					scores.put(t, scores.get(t) + Math.log((double)count / (double)categories.get(t).GetTotalWords()));
				}
				else
				{
					scores.put(t, scores.get(t) + Math.log((double)0.01 / (double)categories.get(t).GetTotalWords()));
				}
			}


		}
		for (Tag t : tags)
		{
			scores.put(t, scores.get(t) + Math.log((double)categories.get(t).GetTotalWords() / (double)CountAllWords()));
		}
		
		double best = -Double.MAX_VALUE;
		Tag tBest = new Tag("none");
		
		for (Tag t : tags)
		{
			if (scores.get(t) > best) {
				best = scores.get(t);
				tBest = t;
			}
				
		}
		
	
		return tBest.GetTagName();
	}

	public void train() {
		System.out.println("\nTraining Naive Bayes Classifier....");
		
		File gen = new File(tagFolderPath);
    	File genFiles[] = gen.listFiles();
        for (File f : genFiles) {
        	if (f.getName().substring(0, "train".length()).compareTo("train") == 0) {
        		LoadTagFile(f.getPath(), new Tag(f.getName().substring("train".length(), f.getName().length())));
        	}
        }
	}
	
	public int testTagFile(String tag, String filepath, PrintWriter pw, Hashtable<String,ArrayList<Integer>> summary) {
		int match = 0;
		int uttCnt = 0;
		int matchRate = -1;
		
//		System.out.println("Testing: " + tag + " " + filepath);
		
		ArrayList<Integer> track = new ArrayList<Integer>();
		
		try {
			BufferedReader bf = new BufferedReader(new FileReader(filepath));
			String utterance;
			
			while ((utterance = bf.readLine()) != null) {
				String bestMatch = classifyUtterance(utterance);
				if (tag.compareTo(bestMatch) == 0) match ++;
				uttCnt ++;
				pw.println(utterance + " " + bestMatch + " [" + tag + "]");
			}
			
			bf.close();
			
			if (uttCnt == 0) return matchRate;
			matchRate = (match * 100) / uttCnt;
			track.add(matchRate);
			track.add(match);
			track.add(uttCnt);
			summary.put(tag, track);
			System.out.println(tag + " match rate: " + matchRate + "% [" + match + "/" + uttCnt + "]");
			pw.println(tag + " match rate: " + matchRate + "% [" + match + "/" + uttCnt + "]\n\n");
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return matchRate;
	}
}
